
/**
 * 更改记录:
 * 		2012.03.08:
 * 			- 删除 KTimerUpdate 类, 为 KTimer 增加控制类型属性, 以控制是手动更新(TYPE_MANUAL), 还是自动更新(TYPE_AUTOMATIC).
 * 			- 增加 manualUpdate 函数, 手动更新必须手动调用 manualUpdate 方法, 自动更新则在 ENTER_FRAME 里自动调用更新函数.
 */

package iks.utils 
{
	import flash.display.*;
	import flash.events.*;
	import iks.iface.*;
	
	/**
	 * 自定义的计时器, 使用基本与 AS3 的 Timer 一致.
	 * 当不再引用时一定要调用dispose方法, 手动释放资源.
	 * @author StefanieKaka
	 */
	public final class KTimer extends Shape implements IKDispose
	{
		/// 每当 Timer 对象达到根据 Timer.delay 属性指定的间隔时调度
		public static const KTIMER : String = "KTimer";
		
		/// 每当它完成 Timer.repeatCount 设置的请求数后调度
		public static const KTIMER_COMPLETE : String = "KTimerComplete";
		
		/// 更新方式, 自动化
		public static const TYPE_AUTOMATIC : String = "Type_Automatic";
		
		/// 更新方式, 手动
		public static const TYPE_MANUAL : String = "Type_Manual";
		
		/**
		 * 使用指定的 delay 和 repeatCount 状态构造新的 Timer 对象.
		 * 计时器不会自动启动；必须调用 start() 方法来启动它.
		 * @param	delay 计时器事件间的延迟（以毫秒为单位）
		 * @param	repeatCount 指定重复次数
		 * @param	operatorType 更新类型, 有手动(KTimer.TYPE_MANUAL)和自动(TYPE_AUTOMATIC), 选择手动必须手动调用 manualUpdate 方法.
		 */
		public function KTimer(delay : Number, repeatCount : Number = 0, operatorType : String = TYPE_AUTOMATIC) 
		{
			m_pause = true;
			m_elapse = 0;
			m_delay = delay;
			m_repeatCount = repeatCount;
			m_operateType = operatorType;
			
			// 自动更新模式
			if (m_operateType == TYPE_AUTOMATIC)
				this.addEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
		}
		
///////////////////////////////////////////////////////////////////////////////////////////////////
// 公共域
///////////////////////////////////////////////////////////////////////////////////////////////////
		
		/**
		 * 当前延迟已经经过的时间, 每次派发 KTIMER 事件之后, elapse 为 0
		 */
		public function get elapse() : Number
		{
			return m_elapse;
		}

		/**
		 * 计时器从 0 开始后触发的总次数。 如果已重置了计时器，则只会计入重置后的触发次数。
		 */
		public function get currentCount() : int
		{
			return m_currentCount;
		}

		/**
		 * 计时器事件间的延迟（以毫秒为单位）。 如果在计时器正在运行时设置延迟间隔，则计时器将按相同的 repeatCount 迭代重新启动。
		 * @exception Error 如果指定的延迟为负数或不是有限数，则将引发异常。
		 */
		public function get delay() : Number
		{
			return m_delay;
		}
		
		public function set delay(value : Number) : void
		{
			if (value < 0 || isNaN(value) || !isFinite(value))
				throw new Error("延迟值为无效值");
			
			m_delay = value;
			
			if (running)
			{
				reset();
				start();
			}
			else
			{
				reset();
			}
		}
		
		/**
		 * 设置的计时器运行总次数。 如果重复计数设置为 0，则计时器将持续不断运行，直至调用了 stop() 方法或程序停止。 如果重复计数不为 0，则将运行计时器，运行次数为指定的次数。 如果设置的 repeatCount 总数等于或小于 currentCount，则计时器将停止并且不会再次触发。 
		 */
		public function get repeatCount() : int
		{
			return m_repeatCount;
		}
		
		public function set repeatCount(value : int) : void
		{
			m_repeatCount = value;
			
			if (m_repeatCount != 0 && m_repeatCount <= m_currentCount)
				stop();
		}
		
		/**
		 * 计时器的当前状态；如果计时器正在运行，则为 true，否则为 false。 
		 */
		public function get running() : Boolean
		{
			return !m_pause;
		}
		
		/**
		 * 如果计时器正在运行，则停止计时器，并将 currentCount 属性设回为 0，这类似于秒表的重置按钮。 然后，在调用 start() 后，将运行计时器实例，运行次数为指定的重复次数（由 repeatCount 值设置）。 
		 */
		public function reset() : void
		{
			m_pause = true;
			m_elapse = 0;
			m_currentCount = 0;
		}
		
		/**
		 * 如果计时器尚未运行，则启动计时器。如果计时器到达目标循环次数, 将无法启动, 直到调用 reset 方法.
		 */
		public function start() : void
		{
			if (m_currentCount != m_repeatCount || m_repeatCount == 0)
				m_pause = false;
		}
		
		/**
		 * 停止计时器。 如果在调用 stop() 后调用 start()，则将继续运行计时器实例，运行次数为剩余的 重复次数（由 repeatCount 属性设置）。 
		 */
		public function stop() : void
		{
			m_pause = true;
		}
		
		/**
		 * 手动更新计时器, 如果为自动类型, 则返回值为 null.
		 * @return 计时器如果到达 KTimer.delay 时间返回 KTIMER, 如果到达 KTimer.repeatCount 次数, 返回 KTIME_COMPLETE, 否则返回null
		 */
		public function manualUpdate() : void
		{
			if (m_operateType != TYPE_MANUAL)
				return;
				
			determineUpdate();
		}
		
///////////////////////////////////////////////////////////////////////////////////////////////////
// 实现 IKDispose 接口
///////////////////////////////////////////////////////////////////////////////////////////////////
		
		public function dispose() : void
		{
			if (m_isDisposed)
				return;
			m_isDisposed = true;
			
			stop();
			this.removeEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
		}

///////////////////////////////////////////////////////////////////////////////////////////////////
// 私有域
///////////////////////////////////////////////////////////////////////////////////////////////////
		
		/// 更新计时器
		private function update() : String
		{
			if (m_pause)
				return null;
				
			m_elapse += KTimerManager.interval;
			if (m_elapse >= m_delay)
			{
				m_elapse = 0;
				
				if (m_repeatCount != 0 && ++m_currentCount == m_repeatCount)
				{
					m_pause = true;
					return KTIMER_COMPLETE;
				}
				
				return KTIMER;
			}
			
			return null;
		}
		
		/// 检测确定更新
		private function determineUpdate() : void
		{
			var result : String = update();
			if (result == KTIMER)
				this.dispatchEvent(new Event(KTIMER));
			else if (result == KTIMER_COMPLETE)
				this.dispatchEvent(new Event(KTIMER_COMPLETE));
		}

		/// 更新帧函数
		private function onEnterFrameHandler(evt : Event) : void
		{
			if (m_operateType != TYPE_AUTOMATIC)
				return;
			
			determineUpdate();
		}

		private var m_isDisposed	: Boolean = false;
		private var m_pause			: Boolean = true;		// 是否暂停
		private var m_elapse		: Number = 0;			// 经过时间
		private var m_delay			: Number = 0;			// 延迟
		private var m_currentCount	: int = 0;				// 当前运行次数
		private var m_repeatCount	: int = 0;				// 重复次数
		private var m_operateType	: String = null;		// 操作类型
	}

}

































///////////////////////////////////////////////////////////////////////////////////////////////////
// end file